package com.sea.base.widget

import android.content.Context
import android.content.res.TypedArray
import android.graphics.Canvas
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.GradientDrawable.RECTANGLE
import android.util.AttributeSet
import android.view.Gravity
import android.widget.LinearLayout
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.core.view.forEach
import com.custom.widget.R
import com.sea.base.ext.global.dp
import com.sea.base.ext.global.getCurrentMillis
import com.sea.base.ext.global.toColorInt
import com.sea.base.ext.view.LinearLayoutLayoutParams
import com.sea.base.ext.view.MATCH_PARENT
import com.sea.base.widget.shape.ShapeView

class WaveVoiceAnimView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    LinearLayout(context, attrs, defStyleAttr) {
    private var startColor = com.sea.base.R.color.c_fff.toColorInt(context)
    private var endColor = com.sea.base.R.color.c_000.toColorInt(context)
    private var itemCount = 6
    private var itemMinHeight = 3.5.dp
    private var cycleTimeMillis = 1000
    private var isStart = false
    private var startMillis = 0L

    init {
        if (attrs != null) {
            val ta: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.WaveVoiceAnimView)
            startColor = ta.getColor(R.styleable.WaveVoiceAnimView_startColor, startColor)
            endColor = ta.getColor(R.styleable.WaveVoiceAnimView_endColor, endColor)
            itemCount = ta.getInt(R.styleable.WaveVoiceAnimView_itemCount, itemCount)
            itemMinHeight = ta.getDimensionPixelSize(R.styleable.WaveVoiceAnimView_itemMinHeight, itemMinHeight)
            cycleTimeMillis = ta.getInt(R.styleable.WaveVoiceAnimView_cycleTimeMillis, cycleTimeMillis)
            ta.recycle()
        }
        gravity = Gravity.CENTER
        orientation = HORIZONTAL
        initData()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val mode = MeasureSpec.getMode(heightMeasureSpec)
        if (mode != MeasureSpec.EXACTLY) {
            super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(14.dp, MeasureSpec.EXACTLY))
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        }
    }

    private fun initData() {
        if (itemCount < 3) {
            throw IllegalArgumentException("动画数量不能少于3")
        }
        (0 until itemCount).forEach { index ->
            addView(MyItemView(context, index).apply {
                buildShape().apply {
                    setShape(RECTANGLE)
                    setGradientColors(intArrayOf(startColor, endColor))
                    setCornersRadius(500.dp)
                    setOrientation(GradientDrawable.Orientation.TOP_BOTTOM)
                }
                layoutParams = LinearLayoutLayoutParams(itemMinHeight, MATCH_PARENT).apply {
                    marginStart = itemMinHeight / 4
                    marginEnd = itemMinHeight / 4
                }
            })
        }
    }

    fun start() {
        isStart = true
        startMillis = getCurrentMillis()
        this.forEach {
            (it as MyItemView).invalidate()
        }
    }

    fun pause() {
        isStart = false
    }

    fun stop() {
        isStart = false
        this.forEach {
            (it as MyItemView).reset()
        }
    }

    fun setColorRes(@ColorRes startColor: Int, @ColorRes endColor: Int) {
        setColor(startColor.toColorInt, endColor.toColorInt)
    }

    fun setColor(@ColorInt startColor: Int, @ColorInt endColor: Int) {
        this.startColor = startColor
        this.endColor = endColor
        this.forEach {
            (it as MyItemView).buildShape().apply {
                setGradientColors(intArrayOf(startColor, endColor))
            }
        }
    }

    inner class MyItemView(context: Context, private val index: Int) : ShapeView(context) {

        override fun onDraw(canvas: Canvas) {
            if (isStart) {
                val progress = ((getCurrentMillis() - startMillis) % cycleTimeMillis) / cycleTimeMillis.toFloat()
                //循环修改高度
                buildShape().setSize(itemMinHeight, getItemHeight(progress))
            }
            super.onDraw(canvas)
        }

        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            buildShape().setSize(itemMinHeight, getItemHeight(0f))
        }

        private fun getItemHeight(offsetRatio: Float): Int {
            val centerCount = (itemCount + 2) / 2
            val currentRatio = (index + 1) / centerCount.toFloat()
            val k = (measuredHeight - itemMinHeight) / (centerCount - 1)
            val ratioCache = if (currentRatio < 1) (currentRatio + offsetRatio * 2) else (2f - currentRatio + offsetRatio * 2)
            val x = (
                    when {
                        ratioCache < 1 -> ratioCache
                        ratioCache < 2 -> 2 - ratioCache
                        ratioCache < 3 -> ratioCache - 2
                        else -> 3 - ratioCache
                    }
                    ) * centerCount
            val a = measuredHeight - centerCount * k
            //根据线性函数算出高
            return (k * x + a).toInt()
        }

        fun reset() {
            buildShape().setSize(itemMinHeight, getItemHeight(0f))
        }
    }
}